package com.syl.auth.filter;

import com.syl.auth.authorization.SmallAuthenticationToken;
import com.syl.auth.constant.AuthConstant;
import com.syl.auth.model.LocalUser;
import com.syl.auth.utils.SecurityUtil;
import com.syl.auth.utils.ThreadLocalUserUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @ClassName SmallJwtFilter
 * @Description jwt通用过滤器, 用于解析jwt, 并将用户信息设置到上下文中
 * @Author YunLong
 * @Date 2023/5/3 10:49
 */
@Slf4j
public class SmallJwtFilter extends GenericFilterBean {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) servletRequest;

        if (HttpMethod.OPTIONS.matches(req.getMethod())) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }

        String jwtToken = req.getHeader(AuthConstant.AUTHORIZATION);
        if (!StringUtils.hasText(jwtToken)) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }

        String replaceToken = jwtToken.replace(AuthConstant.BEARER, "");
        Claims claims = null;
        try {
            claims = SecurityUtil.getClaims(replaceToken);
        } catch (Exception e) {
            filterChain.doFilter(servletRequest, servletResponse);
        }

        assert claims != null;
        SmallAuthenticationToken smallAuthenticationToken = this.setLocalUser(claims);
        // security的上下文设置授权信息
        SecurityContextHolder.getContext().setAuthentication(smallAuthenticationToken);
        filterChain.doFilter(req, servletResponse);
    }

    private SmallAuthenticationToken setLocalUser(Claims claims) {
        // 获取当前登录的用户Id
        Long userId = claims.get(AuthConstant.USER_ID, Long.class);
        String username = claims.get(AuthConstant.USERNAME, String.class);
        Long orgId = claims.get(AuthConstant.ORG_ID, Long.class);
        String orgName = claims.get(AuthConstant.ORG_NAME, String.class);
        String roles = claims.get(AuthConstant.ROLES_ID_KEY, String.class);
        // 把当前用户的角色放入到security的上下文中，便于接口的鉴权
        String[] split = roles.split(",");
        List<SimpleGrantedAuthority> authorities = Arrays.asList(split).stream().map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
        LocalUser localUser = new LocalUser().setUserId(userId)
                .setUserName(username)
                .setOrgId(orgId)
                .setOrgName(orgName);
        ThreadLocalUserUtil.setLocalUser(localUser);
        log.debug("now userId:{},username:{}", userId, username);
        return new SmallAuthenticationToken(userId, null, authorities);
    }
}
